#include "hj212_client_port.h"

#define HJ_LOG_TAG  "hj212.port"        // 日志标签
#define HJ_LOG_LVL HJ_DBG_INFO          // 日志等级
#include "hjdebug.h"


#define _____________________HJ212_DATA_CLIENT_____________________
/* 以下是关于HJ212Client的适配 */

#define HJ2112_CLIENT_SEND_INTER (1500)

static rt_list_t hj212_client_list = RT_LIST_OBJECT_INIT(hj212_client_list);

/* 客户端接口 */
static int hj212port_command(struct hj212_client *client, int cmd, void *args);
static time_t hj212port_current_timestamp(void);
static int hj212port_set_current_timestamp(time_t time);
static struct timeval hj212port_current_subsec(void);
static void hj212port_lock(struct hj212_client *client);
static int hj212port_trylock(struct hj212_client *client);
static void hj212port_unlock(struct hj212_client *client);
static int hj212port_dev_open(struct hj212_client *client, int flag);
static int hj212port_dev_close(struct hj212_client *client);
static int hj212port_dev_state(struct hj212_client *client);
static int hj212port_dev_recv(struct hj212_client *client, uint8_t *buffer, int len, int timeout);
static int hj212port_dev_send(struct hj212_client *client, const uint8_t *buffer, int len);
static void hj212port_event_push(struct hj212_client *client, struct hj212_event *event);
static int info_cn_to_index(int cn);
const static struct hj212_client_ops port_hj212_client_ops =
{
    .command = hj212port_command,
    .current_timestamp = hj212port_current_timestamp,
    .set_current_timestamp = hj212port_set_current_timestamp,
    .current_subsec  = hj212port_current_subsec,
    .lock = hj212port_lock,
    .trylock = hj212port_trylock,
    .unlock = hj212port_unlock,
    .malloc = hj212port_malloc,
    .calloc = hj212port_calloc,
    .free = hj212port_free,
    .dev_open = hj212port_dev_open,
    .dev_close = hj212port_dev_close,
    .dev_state = hj212port_dev_state,
    .dev_recv = hj212port_dev_recv,
    .dev_send = hj212port_dev_send,
    .get_data_source = hj212port_get_data_source,
    .create_hisdata_source = hj212port_create_hisdata_source,
    .delete_data_source = hj212port_delete_data_source,
    .event_push = hj212port_event_push,
};

void hj212port_delete_client(struct port_hj212_client *client)
{
    rt_list_remove(&client->list);
    hj212_client_destroy(&client->parent);
    osMutexDelete(client->lock);
    myfree_in(client);
}
struct port_hj212_client *hj212port_create_client(int id, int protocol, void *user)
{
    struct port_hj212_client *client = mymalloc_in(sizeof(struct port_hj212_client));
    if (client)
    {
        hj212_runinfo_block_get_instance(id);   // 创建的时候读一下，初始化铁电

        memset(client, 0, sizeof(*client));
        client->user = user;
        client->send_inter = HJ2112_CLIENT_SEND_INTER;  // 发送间隔
        osMutexAttr_t attr =
        {
            .name = NULL,
            .attr_bits = osMutexRecursive | osMutexPrioInherit,
            .cb_mem = NULL,
            .cb_size = 0,
        };
        client->lock = osMutexNew(&attr);

        if (static_datasource_init(client) < 0)
        {
            osMutexDelete(client->lock);
            myfree_in(client);
            return NULL;
        }
        if (hj212_client_init(&client->parent, id, protocol, &port_hj212_client_ops) < 0)
        {
            osMutexDelete(client->lock);
            myfree_in(client);
            return NULL;
        }

        for (int i = HJ212_MSG_TYPE_RTD; i <= HJ212_MSG_TYPE_DAY; i++)
        {
            strncpy(client->name[i], hj212_datamsg_cn_to_name(hj212_datamsg_cn(i)), sizeof(client->name[i]));
            strcpy(client->content[i], "无记录");
        }

        strcpy(client->name[4], "请求记录1");
        strcpy(client->name[5], "请求记录2");
        strcpy(client->content[4], "无记录");
        strcpy(client->content[5], "无记录");

        rt_list_insert_before(&hj212_client_list, &client->list);
    }
    return client;
}

static int hj212port_command(struct hj212_client *client, int cmd, void *args)
{
    int result = 0;
    struct port_hj212_client *this = (struct port_hj212_client *)client;
    const server_param_t *config = &sys_param->server_param[client->id];
    const base_param_t *base_config = &sys_param->base_param;
    sysparam_lock(config->lock);
    sysparam_lock(base_config->lock);
    switch (cmd)
    {
    case GET_HJ212_SYS_CODE:
        snprintf(args, HJ212_SYSCODE_MAX_LEN, "%d", base_config->sys_code);
        break;
    case GET_HJ212_ACCESS_PWD:
        strncpy(args, config->access_pwd, HJ212_ACCESS_PWD_MAX_LEN);
        break;
    case GET_HJ212_CLIENT_MN:
        strncpy(args, config->mn, HJ212_MN_MAX_LEN);
        break;
    case GET_HJ212_PROTOCOL:
        *((int *)args) = config->comm_prot == HJ212_2005_COMM_PROT_ENUM ?
                         HJ212_PROTOCOL_2005 : HJ212_PROTOCOL_2017;
        break;
    case GET_HJ212_RTD_CYCLE:
        *((int *)args) = config->rtd_inter;
        break;
    case GET_HJ212_MIN_CYCLE:
        *((int *)args) = base_config->save_inter * 60;
        break;
    case GET_HJ212_HEARTBEAT_CYCLE:
        *((int *)args) = config->hearbeat_inter * 60;
        break;
    case GET_HJ212_MAXRET:
        *((int *)args) = config->re_count;
        break;
    case GET_HJ212_SEND_INTER:
        *((int *)args) = this->send_inter;      // 暂时500ms一条数据
        break;
    case GET_HJ212_STREAM_TIMEOUT:
        // *((int *)args) = this->send_inter;      // 流超时直接使用发送间隔
        // *((int *)args) = 3;
        *((int *)args) = config->timeout;           // 流超时时间
        break;
#if 0       // 暂时不支持设置
    case SET_HJ212_SYS_CODE:
        memcpy(this->syscode, args, HJ212_SYSCODE_MAX_LEN);
        break;
    case SET_HJ212_ACCESS_PWD:
        memcpy(this->access_pwd, args, HJ212_ACCESS_PWD_MAX_LEN);
        break;
    case SET_HJ212_CLIENT_MN:
        memcpy(this->client_mn, args, HJ212_MN_MAX_LEN);
        break;
    case SET_HJ212_PROTOCOL:
        this->protocol = *((int *)args);
        break;
    case SET_HJ212_RTD_CYCLE:
        this->rtd_cycle = *((int *)args);
        break;
    case SET_HJ212_MIN_CYCLE:
        this->min_cycle = *((int *)args);
        break;
    case SET_HJ212_HEARTBEAT_CYCLE:
        this->heartbeat_cycle = *((int *)args);
        break;
    case SET_HJ212_MAXRET:
        this->maxret = *((int *)args);
        break;
    case SET_HJ212_SEND_INTER:
        this->send_inter = *((int *)args);
        break;
    case SET_HJ212_STREAM_TIMEOUT:
        // this->send_inter; = *((int *)args)
        break;
#endif
    default:
        result = -1;
        break;
    }
    sysparam_unlock(config->lock);
    sysparam_unlock(base_config->lock);
    HJ_LOG_D("#%d-command=%d, reset=%d", client->id, cmd, result);
    return result;
}
static time_t hj212port_current_timestamp(void)
{
    return rtc_get_timestamp();
}
static int hj212port_set_current_timestamp(time_t time)
{
    return -1;
}
static struct timeval hj212port_current_subsec(void)
{
    struct timeval result;
    /*
    rtc_time_t ms;
    rtc_get_time(&ms);
    result.tv_sec = rtc_get_timestamp();
    result.tv_usec = ms.ms * 1000;
    */
    gettimeofday(&result, NULL);
    return result;
}
int shell_gettimeofday(void)
{
    int i = 20;
    while (i--)
    {
        struct timeval time;
        gettimeofday(&time, NULL);
        printf("time->sec=%ld, time->usec=%ld\r\n", time.tv_sec, time.tv_usec / 1000);
        osDelay(10);
    }
    return 0;
}
SHELL_EXPORT_CMD(gettimeofday, shell_gettimeofday, shell_gettimeofday);


static void hj212port_lock(struct hj212_client *client)
{
    struct port_hj212_client *this = (struct port_hj212_client *)client;
    osMutexWait(this->lock, osWaitForever);
}
static int hj212port_trylock(struct hj212_client *client)
{
    struct port_hj212_client *this = (struct port_hj212_client *)client;
    return osMutexWait(this->lock, 0);
}
static void hj212port_unlock(struct hj212_client *client)
{
    struct port_hj212_client *this = (struct port_hj212_client *)client;
    osMutexRelease(this->lock);
}
void *hj212port_malloc(size_t size)
{
    return mymalloc_ex(size);
}
void *hj212port_calloc(unsigned int num, size_t size)
{
    void *result = mymalloc_ex(size * num);
    if (result)
        memset(result, 0, size * num);
    return result;
}
void hj212port_free(void *ptr)
{
    myfree_ex(ptr);
}
static int hj212port_dev_open(struct hj212_client *client, int flag)
{
    struct port_hj212_client *this = (struct port_hj212_client *)client;
    data_service_device_connect(this->user, 0);
    return 0;
}
static int hj212port_dev_close(struct hj212_client *client)
{
    struct port_hj212_client *this = (struct port_hj212_client *)client;
    data_service_device_disconnect(this->user);
    return 0;
}
static int hj212port_dev_state(struct hj212_client *client)
{
    struct port_hj212_client *this = (struct port_hj212_client *)client;
    return data_service_device_state(this->user);
}
static int hj212port_dev_recv(struct hj212_client *client, uint8_t *buffer, int len, int timeout)
{
    struct port_hj212_client *this = (struct port_hj212_client *)client;
    return data_service_device_recv(this->user, buffer, len, timeout);
}
static int hj212port_dev_send(struct hj212_client *client, const uint8_t *buffer, int len)
{
    struct port_hj212_client *this = (struct port_hj212_client *)client;
    return data_service_device_send(this->user, buffer, len, 0);
}
static int info_cn_to_index(int cn)
{
    if (cn == 2011)
        return 0;
    if (cn == 2051)
        return 1;
    if (cn == 2061)
        return 2;
    if (cn == 2031)
        return 3;

    return -1;
}
static void hj212port_event_push(struct hj212_client *client, struct hj212_event *event)
{
    struct port_hj212_client *this = (struct port_hj212_client *)client;
    /* 处理HJ212抛出的事件 */
    if (event->type == HJ_EVENT_NONE)
        return;
    if (event->type == HJ_EVENT_STREAM_TRANSFER || event->type == HJ_EVENT_STREAM_TRANSFER_TIMEOUT)
    {
        struct hj212_stream_transfer_event *st_event = (void *)event;
        int index = info_cn_to_index(st_event->cn);
        if (index < 0 || index >= HJ212_INFO_NUM)
            return;
        strncpy(this->name[index], hj212_datamsg_cn_to_name(st_event->cn), sizeof(this->name[0]));

        const char *p = NULL;
        if (event->type == HJ_EVENT_STREAM_TRANSFER)
            p = "已发送";
        else
            p = "应答超时";

        struct tm time;
        localtime_r(&st_event->parent.timestamp, &time);
        time.tm_year += 1900;
        time.tm_mon += 1;
        snprintf(this->content[index], sizeof(this->content[0]),
                 "<%04d/%02d/%02d %02d:%02d:%02d> %s",
                 time.tm_year, time.tm_mon, time.tm_mday,
                 time.tm_hour, time.tm_min, time.tm_sec, p);
    }
    else if (event->type == HJ_EVENT_REQUEST ||
             event->type == HJ_EVENT_INVALID_REQUEST ||
             event->type == HJ_EVENT_REQUEST_FAILED ||
             event->type == HJ_EVENT_REQUEST_SUCCESS)
    {
        struct hj212_request_event *r_event = (void *)event;
        int index = this->current_request_info + HJ212_REQUEST_INFO_BASE;
        snprintf(this->name[index], sizeof(this->name[0]), "%d请求", r_event->cn);

        const char *p = NULL;
        if (event->type == HJ_EVENT_REQUEST)
            p = "收到请求";
        else if (event->type == HJ_EVENT_INVALID_REQUEST)
            p = "无效请求";
        else if (event->type == HJ_EVENT_REQUEST_FAILED)
            p = "执行错误";
        else if (event->type == HJ_EVENT_REQUEST_SUCCESS)
            p = "执行成功";
        else
            p = "未知事件";

        struct tm time;
        localtime_r(&event->timestamp, &time);
        time.tm_year += 1900;
        time.tm_mon += 1;
        if (event->type == HJ_EVENT_INVALID_REQUEST || event->type == HJ_EVENT_REQUEST_FAILED)
            snprintf(this->content[index], sizeof(this->content[0]),
                     "<%04d/%02d/%02d %02d:%02d:%02d> %s-%d",
                     time.tm_year, time.tm_mon, time.tm_mday,
                     time.tm_hour, time.tm_min, time.tm_sec,
                     p, r_event->error_code);
        else
            snprintf(this->content[index], sizeof(this->content[0]),
                     "<%04d/%02d/%02d %02d:%02d:%02d> %s",
                     time.tm_year, time.tm_mon, time.tm_mday,
                     time.tm_hour, time.tm_min, time.tm_sec, p);

        if (++this->current_request_info >= HJ212_REQUEST_INFO_NUM)
        {
            this->current_request_info = 0;
        }
    }
}

void hj212_pol_state_push(int polcodeid, int statecodeid, variant_type *value, time_t time)
{
    struct port_hj212_client *client = NULL;
    rt_list_for_each_entry(client, &hj212_client_list, list)
    {
        hj212_pol_state_pushsource(&client->polstate_datasource, polcodeid, statecodeid, value, time);
    }
}

#if 1
int hj212port_pushstate(int no, int state)
{
    struct port_hj212_client *client = NULL;
    rt_list_for_each_entry(client, &hj212_client_list, list)
    {
        if (client->parent.id == no)
        {
            for (int type = 0; type < HJ212_MSG_TYPE_NUM; type++)
            {
                hj212_client_pushstate(&client->parent, type, state);
            }
            break;
        }
    }
    return 0;
}
SHELL_EXPORT_CMD(pushstate, hj212port_pushstate, int hj212port_pushstate(int no, int state));

int hj212port_getpushstate(int no)
{
    struct port_hj212_client *client = NULL;
    rt_list_for_each_entry(client, &hj212_client_list, list)
    {
        if (client->parent.id == no)
        {
            for (int type = 0; type < HJ212_MSG_TYPE_NUM; type++)
            {
                int state = !!get_hj212_client_pushstate(&client->parent, type);
                HJ_LOG_I("#%d type(%d)state(%d)", no, type, state);
                (void)state;
            }
            break;
        }
    }
    return 0;
}
SHELL_EXPORT_CMD(getpush, hj212port_getpushstate, int hj212port_getpushstate(int no));

int hj212port_set_sendinter(int no, int send_inter)
{
    struct port_hj212_client *client = NULL;
    rt_list_for_each_entry(client, &hj212_client_list, list)
    {
        if (client->parent.id == no)
        {
            client->send_inter = abs(send_inter);
            HJ_LOG_I("#%d send_inter=%d", no, send_inter);
        }
    }
    return 0;
}
SHELL_EXPORT_CMD(sendinter, hj212port_set_sendinter, int hj212port_set_sendinter(int no, int send_inter));
#endif

#define _____________________HJ212_DATA_SERVICE_____________________
/* 以下是关于dataservice的适配 */
#if 0
    #define HJ212_INFO_NUM (8)
#endif
struct hj212_data_service_handle
{
    struct data_service_handle parent;
    struct port_hj212_client *client;
#if 0
    /* 实时分钟小时日 反控1 反控2  */
    char name[HJ212_INFO_NUM][16];       // 界面暂时最多显示8条信息
    char content[HJ212_INFO_NUM][32];
#endif
};
static void hj212_data_service_delete(struct data_service *service, struct data_service_handle *handle)
{
    struct hj212_data_service_handle *this = (struct hj212_data_service_handle *)handle;
    hj212port_delete_client(this->client);
    myfree_in(this);
}
static void hj212_data_service_handle(struct data_service *service)
{
    struct hj212_data_service_handle *this = (struct hj212_data_service_handle *)service->handle;
    hj212_handle(&this->client->parent);
}
static void hj212_data_service_begin(struct data_service *service)
{
    struct hj212_data_service_handle *this = (struct hj212_data_service_handle *)service->handle;
    hj212_client_start(&this->client->parent);
}
static void hj212_data_service_end(struct data_service *service)
{
    struct hj212_data_service_handle *this = (struct hj212_data_service_handle *)service->handle;
    hj212_client_stop(&this->client->parent);
}
static int hj212_data_service_try_switch_protocol(struct data_service *service, int protocol)
{
    if (protocol == HJ212_2005_COMM_PROT_ENUM || protocol == HJ212_2017_COMM_PROT_ENUM)
        return 0;
    return -1;
}
/* 补足数据 */
static int hj212_data_service_updata_begin(struct data_service *service, uint32_t type, time_t begin, time_t end)
{
    struct hj212_data_service_handle *this = (struct hj212_data_service_handle *)service->handle;
    hj212_client_updata_begin(&this->client->parent, type, begin, end, 0);
    return 0;
}
/* 同步发送 */
static int hj212_data_service_synchronization(struct data_service *service)
{
    struct hj212_runinfo_block *info = hj212_runinfo_block_get_instance(service->id);
    for (int i = 0; i <= STORAGE_TYPE_YEAR; i++)
    {
        int wptr = storage_get_wptr_pos(i);
        info->rptr[i] = wptr;
    }
    hj212_runinfo_block_save(service->id);
    return 0;
}
int hj212_data_service_info_getnum(struct data_service *service)
{
    return HJ212_INFO_NUM;
}

int hj212_data_service_info_get(struct data_service *service, char *name, char *content, int offset)
{
    if (offset < 0 || offset >= HJ212_INFO_NUM)
        return -1;

    struct hj212_data_service_handle *this = (struct hj212_data_service_handle *)service->handle;

    strcpy(name, this->client->name[offset]);
    strcpy(content, this->client->content[offset]);
    return 0;
}
static const struct data_service_handle_opt hj212_handle_ops =
{
    .delete = hj212_data_service_delete,
    .handle = hj212_data_service_handle,
    .begin = hj212_data_service_begin,
    .end = hj212_data_service_end,
    .try_switch_protocol = hj212_data_service_try_switch_protocol,
    .updata_begin = hj212_data_service_updata_begin,
    .synchronization = hj212_data_service_synchronization,
    .info_getnum = hj212_data_service_info_getnum,
    .info_get = hj212_data_service_info_get,
};
static struct data_service_handle *hj212_data_service_handle_create(struct data_service *service, int protocol)
{
    int hj_protocol;
    if (protocol == HJ212_2005_COMM_PROT_ENUM)
        hj_protocol = HJ212_PROTOCOL_2005;
    else
        hj_protocol = HJ212_PROTOCOL_2017;

    struct hj212_data_service_handle *handle = mymalloc_in(sizeof(struct hj212_data_service_handle));
    if (handle)
    {
        handle->parent.protocol = protocol;
        handle->parent.ops = &hj212_handle_ops;
        handle->parent.service = service;
        handle->client = hj212port_create_client(service->id, hj_protocol, service);
        if (!handle->client)
        {
            myfree_in(handle);
            handle = NULL;
        }
    }
    return (struct data_service_handle *)handle;
}
struct data_service_handle *hj212_2017_data_service_handle_create(struct data_service *service)
{
    return hj212_data_service_handle_create(service, HJ212_2017_COMM_PROT_ENUM);
}
struct data_service_handle *hj212_2005_data_service_handle_create(struct data_service *service)
{
    return hj212_data_service_handle_create(service, HJ212_2005_COMM_PROT_ENUM);
}

